package com.example.common.utils;

import cn.hutool.core.convert.Convert;
import com.example.common.constant.Constants;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
 * 客户端工具类
 */
public class ServletUtils {

    /**
     * 获取String参数
     */
    public static String getParameter(String name) {
        return getRequest().getParameter(name);
    }

    /**
     * 获取String参数
     * Convert.toStr()方法将参数值转换为字符串，
     * 如果参数值为null，则返回默认值defaultValue。
     */
    public static String getParameter(String name, String defaultValue) {
        return Convert.toStr(getRequest().getParameter(name), defaultValue);
    }

    /**
     * 获取Integer参数
     */
    public static Integer getParameterToInt(String name) {
        return Convert.toInt(getRequest().getParameter(name));
    }

    /**
     * 获取Integer参数
     */
    public static Integer getParameterToInt(String name, Integer defaultValue) {
        return Convert.toInt(getRequest().getParameter(name), defaultValue);
    }

    /**
     * 获取Boolean参数
     */
    public static Boolean getParameterToBool(String name) {
        return Convert.toBool(getRequest().getParameter(name));
    }

    /**
     * 获取Boolean参数
     */
    public static Boolean getParameterToBool(String name, Boolean defaultValue) {
        return Convert.toBool(getRequest().getParameter(name), defaultValue);
    }

    /**
     * 获得所有请求参数
     *
     * @param request 请求对象{@link ServletRequest}
     * @return 请求参数Map，键为参数名，值为参数值数组
     */
    public static Map<String, String[]> getParams(ServletRequest request) {
        final Map<String, String[]> params = request.getParameterMap();
        return Collections.unmodifiableMap(params);
    }

    /**
     * 获得所有请求参数，返回一个不可修改的Map
     *
     * @param request
     * @return 请求参数Map，键为参数名，值为参数值的逗号分隔字符串
     */
    public static Map<String, String> getParamMap(HttpServletRequest request) {
        Map<String, String> params = new HashMap<>();
        // 遍历请求参数Map，将每个参数的值转换为逗号分隔的字符串
        // 并将参数名和转换后的字符串放入新的Map中
        for (Map.Entry<String, String[]> entry : getParams(request).entrySet()) {
            params.put(entry.getKey(), StringUtils.join(entry.getValue(), ","));
        }
        return params;
    }

    /**
     * 获取当前请求对象request
     *
     * @return
     */
    public static HttpServletRequest getRequest() {
        return getRequestAttributes().getRequest();
    }

    /**
     * 获取当前请求对象response
     *
     * @return
     */
    public static HttpServletResponse getResponse() {
        return getRequestAttributes().getResponse();
    }

    /**
     * 获取当前请求对象session
     *
     * @return
     */
    public static HttpSession getSession() {
        return getRequest().getSession();
    }

    /**
     * 获取ServletRequestAttributes
     * ServletRequestAttributes这是SpringMVC提供的类，用于获取请求相关的信息，
     * 包括请求参数、请求头、Cookie等
     * 注意：如果在非SpringMVC环境中调用该方法，会抛出ClassCastException异常
     * 因此，在调用该方法之前，需要确保当前线程是在SpringMVC环境中运行的
     */
    public static ServletRequestAttributes getRequestAttributes() {
        RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
        return (ServletRequestAttributes) attributes;
    }

    /**
     * 将字符串渲染到客户端
     * 该方法主要用于将服务器端生成的字符串返回给客户端，
     * 并在客户端使用JavaScript来处理该字符串。
     * 例如，将服务器端生成的JSON字符串返回给客户端，
     * 客户端可以使用JavaScript的JSON.parse()方法来解析该字符串，
     * 并将其转换为JavaScript对象。
     *
     * @param response 渲染对象
     * @param string   待渲染的字符串
     */
    public static void renderString(HttpServletResponse response, String string) {
        try {
            response.setStatus(200);
            response.setContentType("application/json");
            response.setCharacterEncoding("utf-8");
            response.getWriter().print(string);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 是否是Ajax异步请求
     * Ajax异步请求是一种通过XMLHttpRequest对象发送异步请求的方式，
     * 通常用于在不刷新整个页面的情况下，与服务器进行数据交互。
     * 在Ajax异步请求中，客户端会发送一个HTTP请求到服务器，
     * 服务器会处理该请求并返回一个响应。
     * 客户端可以通过JavaScript来处理服务器返回的响应，
     * 例如更新页面的部分内容或触发其他操作。
     *
     * @param request
     */
    public static boolean isAjaxRequest(HttpServletRequest request) {
        String accept = request.getHeader("accept");
        // 如果accept头中包含"application/json"，则说明是Ajax异步请求
        //因为Ajax异步请求的accept头中通常会包含"application/json"
        if (accept != null && accept.contains("application/json")) {
            return true;
        }

        String xRequestedWith = request.getHeader("X-Requested-With");
        // 如果X-Requested-With头中包含"XMLHttpRequest"，则说明是Ajax异步请求
        //因为Ajax异步请求的X-Requested-With头中通常会包含"XMLHttpRequest"
        if (xRequestedWith != null && xRequestedWith.contains("XMLHttpRequest")) {
            return true;
        }

        String uri = request.getRequestURI();
        // 如果请求URI中包含".json"或".xml"，则说明是Ajax异步请求
        //因为在RESTful风格的API中，通常会使用".json"或".xml"来表示返回的数据格式
        if (StringUtils.inStringIgnoreCase(uri, ".json", ".xml")) {
            return true;
        }
        String ajax = request.getParameter("__ajax");
        // 如果请求参数中包含"__ajax"，则说明是Ajax异步请求
        //因为在一些旧版的项目中，可能会使用"__ajax=json"或"__ajax=xml"来表示是否是Ajax异步请求
        return StringUtils.inStringIgnoreCase(ajax, "json", "xml");
    }

    /**
     * 内容编码
     * 比如：
     * 原始内容："你好，世界！"
     * 编码后的内容："%E4%BD%A0%E5%A5%BD%EF%BC%8C%E4%B8%96%E7%95%8C%EF%BC%81"
     *
     * @param str 内容
     * @return 编码后的内容
     */
    public static String urlEncode(String str) {
        try {
            return URLEncoder.encode(str, Constants.UTF8);
        } catch (UnsupportedEncodingException e) {
            return StringUtils.EMPTY;
        }
    }

    /**
     * 内容解码
     * 比如：
     * 编码后的内容："%E4%BD%A0%E5%A5%BD%EF%BC%8C%E4%B8%96%E7%95%8C%EF%BC%81"
     * 解码后的内容："你好，世界！"
     *
     * @param str 编码后的内容
     * @return 解码后的内容
     */
    public static String urlDecode(String str) {
        try {
            return URLDecoder.decode(str, Constants.UTF8);
        } catch (UnsupportedEncodingException e) {
            return StringUtils.EMPTY;
        }
    }
}
